<?php
/**
 * Router
 * 
 * The main router object that handles requests and loads the proper controller.
 * 
 * @package Bedrock
 * @author Nick Williams
 * @version 1.0.0
 * @created 02/30/2008
 * @updated 02/30/2008
 */
class Bedrock_Common_Router extends Bedrock {
	protected $_path;
	protected $_modulePath;
	protected $_args = array();
	protected $_application = 'Bedrock';

	/**
	 * Initializes the router, establishing protected config and logger objects.
	 * 
	 * @param string $appName the name of the application
	 */
	public function __construct($appName) {
		$this->_application = $appName;
		parent::__construct();
	}

	/**
	 * Sets the path to the root directory for all controllers.
	 * 
	 * @param string $path a path holding all needed controllers
	 * @param string $type the type of path to set
	 */
	public function setPath($path, $type = 'standard') {
		Bedrock_Common_Logger::logEntry();
		
		//$path = trim($path, "/\\");

		if(is_dir($path) == false) {
			throw new Exception("Invalid controller path: '" . $path . "'");
		}
		
		if($type == 'standard') {
			Bedrock_Common_Logger::info("Controller path set to: '" . $path . "'");
			$this->_path = $path;
		}
		elseif($type == 'module') {
			Bedrock_Common_Logger::info("Module controller path set to: '" . $path . "'");
			$this->_modulePath = $path;
		}
		
		Bedrock_Common_Logger::logExit();
	}

	/**
	 * Delegates the request to the proper controller.
	 */
	public function delegate() {
		Bedrock_Common_Logger::logEntry();
		
		try {
    		// Setup
            $route = '';
            $parts = array();
            $cmd_path = $this->_path;
            $class = $this->_application . '_Control';
            $thisDir = '';
            $specialCase = false;
            
            // Find Route
            $route = (empty($_GET['route'])) ? '' : $_GET['route'];
            
            if(empty($route)) {
                $route = "index";
            }
            
            Bedrock_Common_Logger::info("Route: " . $route);
            
            // Separate the route into parts.
            $route = trim($route, "/\\");
            $parts = explode("/", $route);
            
            // Find Controller
            if($parts[0] == 'query' || substr($parts[0], 0, 6) == 'query:') {
            	$controller = new Bedrock_Control_Query();
            	$controller->index($parts);
            }
            else {
            	// Handle Stored Special Cases
            	$cases = Bedrock_Common_Router_SpecialCases::retrieve();
            	
            	foreach($cases as $case) {
            		if(substr($route, 0, strlen($case['route'])) == $case['route']) {
            			$controller = new $case['controller']();
            			$controller->{$case['method']}($parts);
            			
            			$specialCase = true;
            			break;
            		}
            	}
            	
            	// Handle Registered Modules
            	$modules = array('applications');
            	
            	if(in_array($parts[0], $modules)) {
            		$cmd_path = $this->_modulePath . DIRECTORY_SEPARATOR . strtolower($parts[0]) . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'Control';
            		$class = $this->_application . '_Module_' . ucwords(array_shift($parts)) . '_Control';
            	}
            	
            	if(!$specialCase) {
		            foreach($parts as $key => $part) {
		                // Check for File/Class
		                $nextPart = '';
		                
		                if(1 < count($parts)) {
		                    $nextPart = $parts[1];
		                }
		                
		                $controller = $this->getClass($cmd_path, $class, $part, $nextPart);
		                
		                if($controller !== false) {
		                    array_shift($parts);
		                    $action = array_shift($parts);
		                    
		                    if(empty($action)) {
		                        $action = 'index';
		                    }
		                    
		                    $args = $parts;
		                    
		                    $controller->$action($args);
		                    break;
		                }
		                
		                // Check for Directory
		                if(is_dir($cmd_path . DIRECTORY_SEPARATOR . $part)) {
		                    $cmd_path .= DIRECTORY_SEPARATOR . ucwords($part);
		                    $thisDir = $part;
		                    $class .= '_' . ucwords($part);
		                    array_shift($parts);
		                }
		                else {
		                    throw new Bedrock_Common_Router_Exception('No controller found using route: "' . $route . '"');
		                }
		            }
            	}
            }
			
			Bedrock_Common_Logger::logExit();
		}
		catch(Bedrock_Common_Router_Exception $ex) {
			Bedrock_Common_Logger::exception($ex);
			Bedrock_Common_Logger::logExit();
			$this->delegateToError();
		}
	}
	
	/**
	 * Attempts to instantiate a class using the specified parameters.
	 *
	 * @param string $basePath the base path for the class file
	 * @param string $baseName the base name for the class
	 * @param string $partA the first element in the parts array
	 * @param string $partB the second element in the parts array
	 * @return mixed either the class if it exists, or false if otherwise
	 */
	protected function getClass($basePath, $baseName, $partA, $partB) {
	    // Setup
	    $result = false;
	    $fileName = ucwords($partA) . '.php';
	    $className = $baseName . '_' . ucwords($partA);
	    $functionName = $partB;
	    $file = '';
	    $class = NULL;
	    
	    // Check for a file with this path.
	    $file = $basePath . DIRECTORY_SEPARATOR . $fileName;
	    
	    if(is_file($file) && is_readable($file)) {
	        // Instantiate Class
            include $file;
            
            $class = new $className();
            
            if(empty($functionName)) {
                $functionName = 'index';
            }
            
            // Check for Action
            if(is_callable(array($class, $functionName))) {
                $result = $class;
            }
	    }
	    
	    return $result;
	}

	/**
	 * Delegates the request to an error dialog.
	 */
	private function delegateToError() {
		Bedrock_Common_Logger::logEntry();
		
//		$file = $this->_path . DIRECTORY_SEPARATOR . 'Error.php';
//		$controller = $this->_application . 'Bedrock_Control_Error';
//		$action = 'http_404';
//		$class = $controller;
//		
//		include ($file);
//		
//		$controller = new $class();
//		$controller->$action(array());
		
		Bedrock_Common_Logger::logExit();
	}
}
?>